基础图形绘制-椭圆
中点画椭圆
基础
首先,我们考虑中点在 ( 0 , 0 ) (0,0) ( 0 , 0 ) 的椭圆。
根据椭圆的对称性,我们只需要画出第一象限的 1 4 \frac{1}{4} 4 1 的圆弧,即可通过对称画出整个椭圆。
中点在 ( 0 , 0 ) (0,0) ( 0 , 0 ) ,焦点在坐标轴上的椭圆的标准方程为:x 2 a 2 + y 2 b 2 = 1 \frac{x^2}{a^2}+\frac{y^2}{b^2}=1 a 2 x 2 + b 2 y 2 = 1 ,隐函数为:F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 F(x,y)=b^2x^2+a^2y^2-a^2b^2=0 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 ,代入各点,有:
当 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 F(x,y)=b^2x^2+a^2y^2-a^2b^2=0 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 时,点在椭圆上;
当 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 > 0 F(x,y)=b^2x^2+a^2y^2-a^2b^2 \gt 0 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 > 0 时,点在椭圆外;
当 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 < 0 F(x,y)=b^2x^2+a^2y^2-a^2b^2 \lt 0 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 < 0 时,点在椭圆内。
考虑画右上方的 1 4 \frac{1}{4} 4 1 圆弧,根据法向量将椭圆弧分成A、B两部分:
对 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 F(x,y)=b^2x^2+a^2y^2-a^2b^2=0 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 分别对 x x x 、y y y 求偏导得 ( x , y ) (x,y) ( x , y ) 处的法向量方向为 ( 2 b 2 x , 2 a 2 y ) (2b^2x,2a^2y) ( 2 b 2 x , 2 a 2 y ) ,有:
当 2 b 2 x < 2 a 2 y 2b^2x\lt2a^2y 2 b 2 x < 2 a 2 y 时,x x x 方向法向量分量较小,水平方向较平缓,列入部分 A A A ;
当 2 b 2 x > 2 a 2 y 2b^2x\gt2a^2y 2 b 2 x > 2 a 2 y 时,y y y 方向法向量分量较小,垂直方向较平缓,列入部分 B B B 。
部分 A
假设当前点在 ( x , y ) (x,y) ( x , y ) ,考虑下一个点选择 ( x + 1 , y ) (x+1,y) ( x + 1 , y ) 还是 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 。
下一个点显然是选择 离椭圆弧更近的点 ,我们可以通过判断 ( x + 1 , y − 0.5 ) (x+1,y-0.5) ( x + 1 , y − 0.5 ) 在 椭圆内 还是 椭圆外 ,来判断 ( x + 1 , y ) (x+1,y) ( x + 1 , y ) 、 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 哪个离圆弧更近(需要注意的是:如果 ( x + 1 , y − 0.5 ) (x+1,y-0.5) ( x + 1 , y − 0.5 ) 恰好在椭圆上 ,算法选择 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 来作为下一个点)。
也就是说,对于 ( x , y ) (x,y) ( x , y ) ,我们判断
d = F ( x + 1 , y − 0.5 ) = b 2 ( x + 1 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 \begin{aligned}
d &= F(x+1,y-0.5)\\
&= b^2(x+1)^2+a^2(y-0.5)^2-a^2b^2\\
&= b^2x^2+a^2y^2+2b^2x-a^2y+0.25a^2+b^2-a^2b^2
\end{aligned}
d = F ( x + 1 , y − 0.5 ) = b 2 ( x + 1 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2
的值,来判断下一个点的选择情况。
若 d < 0 d \lt 0 d < 0 ,选择 ( x + 1 , y ) (x+1,y) ( x + 1 , y ) 作为下一个点。
此时,判断 ( x + 1 , y ) (x+1,y) ( x + 1 , y ) 的下一个点的判断值为:
d ′ = F ( ( x + 1 ) + 1 , ( y ) − 0.5 ) = F ( x + 2 , y − 0.5 ) = b 2 ( x + 2 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 4 b 2 x − a 2 y + 0.25 a 2 + 4 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 ) + 2 b 2 x + 3 b 2 = d + 2 b 2 x + 3 b 2 \begin{aligned}
d' &= F((x+1)+1,(y)-0.5)\\
&= F(x+2,y-0.5)\\
&= b^2(x+2)^2+a^2(y-0.5)^2-a^2b^2\\
&= b^2x^2+a^2y^2+4b^2x-a^2y+0.25a^2+4b^2-a^2b^2\\
&= (b^2x^2+a^2y^2+2b^2x-a^2y+0.25a^2+b^2-a^2b^2)+2b^2x+3b^2\\
&= d+2b^2x+3b^2
\end{aligned}
d ′ = F (( x + 1 ) + 1 , ( y ) − 0.5 ) = F ( x + 2 , y − 0.5 ) = b 2 ( x + 2 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 4 b 2 x − a 2 y + 0.25 a 2 + 4 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 ) + 2 b 2 x + 3 b 2 = d + 2 b 2 x + 3 b 2
若 d ≥ 0 d \ge 0 d ≥ 0 ,选择 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 作为下一个点。
此时,判断 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 的下一个点的判断值为:
d ′ = F ( ( x + 1 ) + 1 , ( y − 1 ) − 0.5 ) = F ( x + 2 , y − 1.5 ) = b 2 ( x + 2 ) 2 + a 2 ( y − 1.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 4 b 2 x − 3 a 2 y + 2.25 a 2 + 4 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 ) + 2 b 2 x − 2 a 2 y + 2 a 2 + 3 b 2 = d + 2 b 2 x − 2 a 2 y + 2 a 2 + 3 b 2 \begin{aligned}
d' &= F((x+1)+1,(y-1)-0.5)\\
&= F(x+2,y-1.5)\\
&= b^2(x+2)^2+a^2(y-1.5)^2-a^2b^2\\
&= b^2x^2+a^2y^2+4b^2x-3a^2y+2.25a^2+4b^2-a^2b^2\\
&= (b^2x^2+a^2y^2+2b^2x-a^2y+0.25a^2+b^2-a^2b^2)+2b^2x-2a^2y+2a^2+3b^2\\
&= d+2b^2x-2a^2y+2a^2+3b^2
\end{aligned}
d ′ = F (( x + 1 ) + 1 , ( y − 1 ) − 0.5 ) = F ( x + 2 , y − 1.5 ) = b 2 ( x + 2 ) 2 + a 2 ( y − 1.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 4 b 2 x − 3 a 2 y + 2.25 a 2 + 4 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 ) + 2 b 2 x − 2 a 2 y + 2 a 2 + 3 b 2 = d + 2 b 2 x − 2 a 2 y + 2 a 2 + 3 b 2
这样我们就可以递推 d d d 的值,不断选择点并更新判断值。
同时考虑初始点 ( 0 , b ) (0,b) ( 0 , b ) ,显然有:
d 0 = F ( 0 + 1 , b − 0.5 ) = b 2 + a 2 ( b − 0.5 ) 2 − a 2 b 2 = b 2 + 0.25 a 2 − a 2 b \begin{aligned}
d_0 &= F(0+1,b-0.5)\\
&= b^2+a^2(b-0.5)^2-a^2b^2\\
&= b^2+0.25a^2-a^2b
\end{aligned}
d 0 = F ( 0 + 1 , b − 0.5 ) = b 2 + a 2 ( b − 0.5 ) 2 − a 2 b 2 = b 2 + 0.25 a 2 − a 2 b
这样,我们就可以画出A部分的椭圆。
部分 B
假设当前点在 ( x , y ) (x,y) ( x , y ) ,考虑下一个点选择 ( x , y − 1 ) (x,y-1) ( x , y − 1 ) 还是 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 。
下一个点显然是选择 离椭圆弧更近的点 ,我们可以通过判断 ( x + 0.5 , y − 1 ) (x+0.5,y-1) ( x + 0.5 , y − 1 ) 在 椭圆外 还是 椭圆内 ,来判断 ( x , y − 1 ) (x,y-1) ( x , y − 1 ) 、 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 哪个离圆弧更近(需要注意的是:如果 ( x + 0.5 , y − 1 ) (x+0.5,y-1) ( x + 0.5 , y − 1 ) 恰好在椭圆上 ,算法选择 ( x , y − 1 ) (x,y-1) ( x , y − 1 ) 来作为下一个点)。
也就是说,对于 ( x , y ) (x,y) ( x , y ) ,我们判断
d = F ( x + 0.5 , y − 1 ) = b 2 ( x + 0.5 ) 2 + a 2 ( y − 1 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2 \begin{aligned}
d &= F(x+0.5,y-1)\\
&= b^2(x+0.5)^2+a^2(y-1)^2-a^2b^2\\
&= b^2x^2+a^2y^2+b^2x-2a^2y+a^2+0.25b^2-a^2b^2
\end{aligned}
d = F ( x + 0.5 , y − 1 ) = b 2 ( x + 0.5 ) 2 + a 2 ( y − 1 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2
的值,来判断下一个点的选择情况。
若 d ≥ 0 d \ge 0 d ≥ 0 ,选择 ( x , y − 1 ) (x,y-1) ( x , y − 1 ) 作为下一个点。
此时,判断 ( x , y − 1 ) (x,y-1) ( x , y − 1 ) 的下一个点的判断值为:
d ′ = F ( ( x ) + 0.5 , ( y − 1 ) − 1 ) = F ( x + 0.5 , y − 2 ) = b 2 ( x + 0.5 ) 2 + a 2 ( y − 2 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + b 2 x − 4 a 2 y + 4 a 2 + 0.25 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2 ) − 2 a 2 y + 3 a 2 = d − 2 a 2 y + 3 b 2 \begin{aligned}
d' &= F((x)+0.5,(y-1)-1)\\
&= F(x+0.5,y-2)\\
&= b^2(x+0.5)^2+a^2(y-2)^2-a^2b^2\\
&= b^2x^2+a^2y^2+b^2x-4a^2y+4a^2+0.25b^2-a^2b^2\\
&= (b^2x^2+a^2y^2+b^2x-2a^2y+a^2+0.25b^2-a^2b^2)-2a^2y+3a^2\\
&= d-2a^2y+3b^2
\end{aligned}
d ′ = F (( x ) + 0.5 , ( y − 1 ) − 1 ) = F ( x + 0.5 , y − 2 ) = b 2 ( x + 0.5 ) 2 + a 2 ( y − 2 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + b 2 x − 4 a 2 y + 4 a 2 + 0.25 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2 ) − 2 a 2 y + 3 a 2 = d − 2 a 2 y + 3 b 2
若 d < 0 d \lt 0 d < 0 ,选择 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 作为下一个点。
此时,判断 ( x + 1 , y − 1 ) (x+1,y-1) ( x + 1 , y − 1 ) 的下一个点的判断值为:
d ′ = F ( ( x + 1 ) + 0.5 , ( y − 1 ) − 1 ) = F ( x + 1.5 , y − 2 ) = b 2 ( x + 1.5 ) 2 + a 2 ( y − 2 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 3 b 2 x − 4 a 2 y + 4 a 2 + 2.25 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2 ) + 2 b 2 x − 2 a 2 y + 3 a 2 + 2 b 2 = d + 2 b 2 x − 2 a 2 y + 3 a 2 + 2 b 2 \begin{aligned}
d' &= F((x+1)+0.5,(y-1)-1)\\
&= F(x+1.5,y-2)\\
&= b^2(x+1.5)^2+a^2(y-2)^2-a^2b^2\\
&= b^2x^2+a^2y^2+3b^2x-4a^2y+4a^2+2.25b^2-a^2b^2\\
&= (b^2x^2+a^2y^2+b^2x-2a^2y+a^2+0.25b^2-a^2b^2)+2b^2x-2a^2y+3a^2+2b^2\\
&= d+2b^2x-2a^2y+3a^2+2b^2
\end{aligned}
d ′ = F (( x + 1 ) + 0.5 , ( y − 1 ) − 1 ) = F ( x + 1.5 , y − 2 ) = b 2 ( x + 1.5 ) 2 + a 2 ( y − 2 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 3 b 2 x − 4 a 2 y + 4 a 2 + 2.25 b 2 − a 2 b 2 = ( b 2 x 2 + a 2 y 2 + b 2 x − 2 a 2 y + a 2 + 0.25 b 2 − a 2 b 2 ) + 2 b 2 x − 2 a 2 y + 3 a 2 + 2 b 2 = d + 2 b 2 x − 2 a 2 y + 3 a 2 + 2 b 2
这样我们就可以递推 d d d 的值,不断选择点并更新判断值。
同时考虑初始点,也就是 部分A 的结束点,设为 ( x , y ) (x,y) ( x , y ) ,显然有:
d 0 = F ( x + 1 , y − 0.5 ) = b 2 ( x + 1 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2 \begin{aligned}
d_0 &= F(x+1,y-0.5)\\
&= b^2(x+1)^2+a^2(y-0.5)^2-a^2b^2\\
&= b^2x^2+a^2y^2+2b^2x-a^2y+0.25a^2+b^2-a^2b^2
\end{aligned}
d 0 = F ( x + 1 , y − 0.5 ) = b 2 ( x + 1 ) 2 + a 2 ( y − 0.5 ) 2 − a 2 b 2 = b 2 x 2 + a 2 y 2 + 2 b 2 x − a 2 y + 0.25 a 2 + b 2 − a 2 b 2
这样,我们就可以画出基础的椭圆。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 static int dx[] = { 1 , 1 , -1 , -1 };static int dy[] = { 1 , -1 , 1 , -1 };static void Normalize (float & x, float & y) { x = (x - (SCR_WIDTH / 2 )) / (SCR_WIDTH / 2 ); y = (y - (SCR_HEIGHT / 2 )) / (SCR_HEIGHT / 2 ); } static void MiddlePoint (int x0, int y0, int a, int b) { int sqrA = a * a, sqrB = b * b; int x = 0 , y = b; double d = sqrB + 0.25 * sqrA - sqrA * b; while (2 * sqrB * x < 2 * sqrA * y) { if (d < 0 ) d = d + 2 * sqrB * x + 3 * sqrB; else d = d + 2 * sqrB * x - 2 * sqrA * y + 2 * sqrA + 3 * sqrB, y--; x++; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } d = sqrB * (x + 0.5 ) * (x + 0.5 ) + sqrA * (y - 1 ) * (y - 1 ) - sqrA * sqrB; while (y >= 0 ) { if (d >= 0 ) d = d - 2 * sqrA * y + 3 * sqrB; else d = d + 2 * sqrB * x - 2 * sqrA * y + 3 * sqrA + 2 * sqrB, x++; y--; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } }
Bresenham
Bresenham 算法是对 中点画椭圆 算法的改进。
我们发现 中点画椭圆 算法中 d d d 的值涉及到过多的浮点数运算,Bresenham 将浮点数运算给取消。
观察 中点画椭圆 算法,发现最小的浮点数为 0.25 0.25 0.25 ,于是我们将所有运算扩大四倍,就可以达到消除浮点运算的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 static int dx[] = { 1 , 1 , -1 , -1 };static int dy[] = { 1 , -1 , 1 , -1 };static void Normalize (float & x, float & y) { x = (x - (SCR_WIDTH / 2 )) / (SCR_WIDTH / 2 ); y = (y - (SCR_HEIGHT / 2 )) / (SCR_HEIGHT / 2 ); } static void Bresenham (int x0, int y0, int a, int b) { int sqrA = a * a, sqrB = b * b; int x = 0 , y = b, d = 4 * sqrB + sqrA - 4 * sqrA * b; while (sqrB * x < sqrA * y) { if (d < 0 ) d = d + 4 * (2 * sqrB * x + 3 * sqrB); else d = d + 4 * (2 * sqrB * x - 2 * sqrA * y + 2 * sqrA + 3 * sqrB), y--; x++; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } d = 4 * sqrB * x * x + 4 * sqrA * y * y + 4 * 2 * sqrB * x - sqrA * y + sqrA + 4 * sqrB - 4 * sqrA * sqrB; while (y >= 0 ) { if (d >= 0 ) d = d - 4 * (2 * sqrA * y + 3 * sqrB); else d = d + 4 * (2 * sqrB * x - 2 * sqrA * y + 3 * sqrA + 2 * sqrB), x++; y--; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } }
OpenGL 完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 #define GLEW_STATIC #include <GL/glew.h> #include <GL/GL.h> #include <GLFW/glfw3.h> #include <iostream> #pragma region Setting static GLFWwindow* window;const unsigned int SCR_WIDTH = 800 ;const unsigned int SCR_HEIGHT = 600 ;const unsigned int MAX_COUNT = 800 * 600 ;static void InitializeWindow () { glfwInit (); glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3 ); glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3 ); glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow (SCR_WIDTH, SCR_HEIGHT, "Test" , NULL , NULL ); glfwMakeContextCurrent (window); glfwSetFramebufferSizeCallback (window, [](GLFWwindow* window, int width, int height) { glViewport (0 , 0 , width, height); }); glewExperimental = GL_TRUE; glewInit (); } static void ProcessInput (GLFWwindow* window) { if (glfwGetKey (window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose (window, true ); } #pragma endregion #pragma region InitializeVertex static float vertices[MAX_COUNT * 3 ];static unsigned int VAO, VBO;static unsigned int count = 0 ;static int dx[] = { 1 , 1 , -1 , -1 };static int dy[] = { 1 , -1 , 1 , -1 };static void Normalize (float & x, float & y) { x = (x - (SCR_WIDTH / 2 )) / (SCR_WIDTH / 2 ); y = (y - (SCR_HEIGHT / 2 )) / (SCR_HEIGHT / 2 ); } static void MiddlePoint (int x0, int y0, int a, int b) { int sqrA = a * a, sqrB = b * b; int x = 0 , y = b; double d = sqrB + 0.25 * sqrA - sqrA * b; while (2 * sqrB * x < 2 * sqrA * y) { if (d < 0 ) d = d + 2 * sqrB * x + 3 * sqrB; else d = d + 2 * sqrB * x - 2 * sqrA * y + 2 * sqrA + 3 * sqrB, y--; x++; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } d = sqrB * x * x + sqrA * y * y + 2 * sqrB * x - sqrA * y + 0.25 * sqrA + sqrB - sqrA * sqrB; while (y >= 0 ) { if (d >= 0 ) d = d - 2 * sqrA * y + 3 * sqrB; else d = d + 2 * sqrB * x - 2 * sqrA * y + 3 * sqrA + 2 * sqrB, x++; y--; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } } static void Bresenham (int x0, int y0, int a, int b) { int sqrA = a * a, sqrB = b * b; int x = 0 , y = b, d = 4 * sqrB + sqrA - 4 * sqrA * b; while (sqrB * x < sqrA * y) { if (d < 0 ) d = d + 4 * (2 * sqrB * x + 3 * sqrB); else d = d + 4 * (2 * sqrB * x - 2 * sqrA * y + 2 * sqrA + 3 * sqrB), y--; x++; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } d = 4 * sqrB * x * x + 4 * sqrA * y * y + 4 * 2 * sqrB * x - sqrA * y + sqrA + 4 * sqrB - 4 * sqrA * sqrB; while (y >= 0 ) { if (d >= 0 ) d = d - 4 * (2 * sqrA * y + 3 * sqrB); else d = d + 4 * (2 * sqrB * x - 2 * sqrA * y + 3 * sqrA + 2 * sqrB), x++; y--; for (int i = 0 ; i < 4 ; i++) { vertices[count * 3 ] = x * dx[i] + x0, vertices[count * 3 + 1 ] = y * dy[i] + y0; Normalize (vertices[count * 3 ], vertices[count * 3 + 1 ]), count++; } } } static void InitializeVertex () { glGenVertexArrays (1 , &VAO); glGenBuffers (1 , &VBO); glBindVertexArray (VAO); glBindBuffer (GL_ARRAY_BUFFER, VBO); glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer (0 , 3 , GL_FLOAT, GL_FALSE, 3 * sizeof (float ), (void *)0 ); glEnableVertexAttribArray (0 ); } #pragma endregion void Render () { glClearColor (0.5 , 0.5 , 0.5 , 1 ); glClear (GL_COLOR_BUFFER_BIT); glBindVertexArray (VAO); glDrawArrays (GL_POINTS, 0 , count); } int main () { int x0, y0, a, b; std::cin >> x0 >> y0 >> a >> b; InitializeWindow (); MiddlePoint (x0, y0, a, b); Bresenham (x0, y0, a, b); InitializeVertex (); while (!glfwWindowShouldClose (window)) { ProcessInput (window); Render (); glfwSwapBuffers (window); glfwPollEvents (); } glfwTerminate (); return 0 ; }